﻿/*
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at 
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *  
 *  Copyright © 2011 Sebastian Ritter
 */
using System;
using java = biz.ritter.javapi;

namespace biz.ritter.javapi.lang.reflect
{

    /**
     * This class provides static methods to decode class and member modifiers.
     *
     * @see Class#getModifiers()
     * @see Member#getModifiers()
     */
    public class Modifier
    {

        /**
         * The {@code int} value representing the {@code public}
         * modifier.
         */
        public static readonly int PUBLIC = 0x1;

        /**
         * The {@code int} value representing the {@code private}
         * modifier.
         */
        public static readonly int PRIVATE = 0x2;

        /**
         * The {@code int} value representing the {@code protected}
         * modifier.
         */
        public static readonly int PROTECTED = 0x4;

        /**
         * The {@code int} value representing the {@code static} modifier.
         */
        public static readonly int STATIC = 0x8;

        /**
         * The {@code int} value representing the {@code readonly} modifier.
         */
        public static readonly int FINAL = 0x10;

        /**
         * The {@code int} value representing the {@code synchronized}
         * modifier.
         */
        public static readonly int SYNCHRONIZED = 0x20;

        /**
         * The {@code int} value representing the {@code volatile}
         * modifier.
         */
        public static readonly int VOLATILE = 0x40;

        /**
         * The {@code int} value representing the {@code transient}
         * modifier.
         */
        public static readonly int TRANSIENT = 0x80;

        /**
         * The {@code int} value representing the {@code native} modifier.
         */
        public static readonly int NATIVE = 0x100;

        /**
         * The {@code int} value representing the {@code interface}
         * modifier.
         */
        public static readonly int INTERFACE = 0x200;

        /**
         * The {@code int} value representing the {@code abstract}
         * modifier.
         */
        public static readonly int ABSTRACT = 0x400;

        /**
         * The {@code int} value representing the {@code strict} modifier.
         */
        public static readonly int STRICT = 0x800;

        // Non-public types required by Java 5 update to class file format
        static readonly int BRIDGE = 0x40;

        static readonly int VARARGS = 0x80;

        static readonly int SYNTHETIC = 0x1000;

        static readonly int ANNOTATION = 0x2000;

        static readonly int ENUM = 0x4000;

        /**
         * Constructs a new {@code Modifier} instance.
         */
        public Modifier()
        {
        }

        /**
         * Indicates whether or not the specified modifiers contain the {@code
         * abstract} modifier.
         * 
         * @param modifiers
         *            the modifiers to test
         * @return {@code true} if the specified modifiers contain the {@code
         *         abstract} modifier, {@code false} otherwise
         */
        public static bool isAbstract(int modifiers)
        {
            return ((modifiers & ABSTRACT) != 0);
        }

        /**
         * Indicates whether or not the specified modifiers contain the {@code
         * readonly} modifier.
         * 
         * @param modifiers
         *            the modifiers to test
         * @return {@code true} if the specified modifiers contain the {@code
         *         readonly} modifier, {@code false} otherwise
         */
        public static bool isFinal(int modifiers)
        {
            return ((modifiers & FINAL) != 0);
        }

        /**
         * Indicates whether or not the specified modifiers contain the {@code
         * interface} modifier.
         * 
         * @param modifiers
         *            the modifiers to test
         * @return {@code true} if the specified modifiers contain the {@code
         *         interface} modifier, {@code false} otherwise
         */
        public static bool isInterface(int modifiers)
        {
            return ((modifiers & INTERFACE) != 0);
        }

        /**
         * Indicates whether or not the specified modifiers contain the {@code
         * native} modifier.
         * 
         * @param modifiers
         *            the modifiers to test
         * @return {@code true} if the specified modifiers contain the {@code
         *         native} modifier, {@code false} otherwise
         */
        public static bool isNative(int modifiers)
        {
            return ((modifiers & NATIVE) != 0);
        }

        /**
         * Indicates whether or not the specified modifiers contain the {@code
         * private} modifier.
         * 
         * @param modifiers
         *            the modifiers to test
         * @return {@code true} if the specified modifiers contain the {@code
         *         private} modifier, {@code false} otherwise
         */
        public static bool isPrivate(int modifiers)
        {
            return ((modifiers & PRIVATE) != 0);
        }

        /**
         * Indicates whether or not the specified modifiers contain the {@code
         * protected} modifier.
         * 
         * @param modifiers
         *            the modifiers to test
         * @return {@code true} if the specified modifiers contain the {@code
         *         protected} modifier, {@code false} otherwise
         */
        public static bool isProtected(int modifiers)
        {
            return ((modifiers & PROTECTED) != 0);
        }

        /**
         * Indicates whether or not the specified modifiers contain the {@code
         * public} modifier.
         * 
         * @param modifiers
         *            the modifiers to test
         * @return {@code true} if the specified modifiers contain the {@code
         *         public} modifier, {@code false} otherwise
         */
        public static bool isPublic(int modifiers)
        {
            return ((modifiers & PUBLIC) != 0);
        }

        /**
         * Indicates whether or not the specified modifiers contain the {@code
         * static} modifier.
         * 
         * @param modifiers
         *            the modifiers to test
         * @return {@code true} if the specified modifiers contain the {@code
         *         static} modifier, {@code false} otherwise
         */
        public static bool isStatic(int modifiers)
        {
            return ((modifiers & STATIC) != 0);
        }

        /**
         * Indicates whether or not the specified modifiers contain the {@code
         * strict} modifier.
         * 
         * @param modifiers
         *            the modifiers to test
         * @return {@code true} if the specified modifiers contain the {@code
         *         strict} modifier, {@code false} otherwise
         */
        public static bool isStrict(int modifiers)
        {
            return ((modifiers & STRICT) != 0);
        }

        /**
         * Indicates whether or not the specified modifiers contain the {@code
         * synchronized} modifier.
         * 
         * @param modifiers
         *            the modifiers to test
         * @return {@code true} if the specified modifiers contain the {@code
         *         synchronized} modifier, {@code false} otherwise
         */
        public static bool isSynchronized(int modifiers)
        {
            return ((modifiers & SYNCHRONIZED) != 0);
        }

        /**
         * Indicates whether or not the specified modifiers contain the {@code
         * transient} modifier.
         * 
         * @param modifiers
         *            the modifiers to test
         * @return {@code true} if the specified modifiers contain the {@code
         *         transient} modifier, {@code false} otherwise
         */
        public static bool isTransient(int modifiers)
        {
            return ((modifiers & TRANSIENT) != 0);
        }

        /**
         * Indicates whether or not the specified modifiers contain the {@code
         * volatile} modifier.
         * 
         * @param modifiers
         *            the modifiers to test
         * @return {@code true} if the specified modifiers contain the {@code
         *         volatile} modifier, {@code false} otherwise
         */
        public static bool isVolatile(int modifiers)
        {
            return ((modifiers & VOLATILE) != 0);
        }

        /**
         * Returns a string containing the string representation of all modifiers
         * present in the specified modifiers. Modifiers appear in the order
         * specified by the Java Language Specification:
         *
         * {@code public private protected abstract static readonly transient volatile native synchronized interface strict}
         *
         * @param modifiers
         *            the modifiers to print
         * @return a printable representation of the modifiers
         */
        public static String toString(int modifiers)
        {
            StringBuilder buf = new StringBuilder();

            if (isPublic(modifiers))
            {
                buf.append("public ");
            }
            if (isProtected(modifiers))
            {
                buf.append("protected ");
            }
            if (isPrivate(modifiers))
            {
                buf.append("private ");
            }
            if (isAbstract(modifiers))
            {
                buf.append("abstract ");
            }
            if (isStatic(modifiers))
            {
                buf.append("static ");
            }
            if (isFinal(modifiers))
            {
                buf.append("readonly ");
            }
            if (isTransient(modifiers))
            {
                buf.append("transient ");
            }
            if (isVolatile(modifiers))
            {
                buf.append("volatile ");
            }
            if (isSynchronized(modifiers))
            {
                buf.append("synchronized ");
            }
            if (isNative(modifiers))
            {
                buf.append("native ");
            }
            if (isStrict(modifiers))
            {
                buf.append("strictfp ");
            }
            if (isInterface(modifiers))
            {
                buf.append("interface ");
            }
            if (buf.length() == 0)
            {
                return "";
            }
            buf.setLength(buf.length() - 1);
            return buf.toString();
        }
    }
}